<script setup lang="ts">
import { ref, nextTick, watch } from 'vue'
import { type role, type status, type File, type Message } from './types.ts'
const messageList = ref<Message[]>([])
const messageContainer = ref<HTMLDivElement | null>(null)
const userScrolled = ref<boolean>(false)
const handleScroll = () => {
  if (messageContainer.value) {
    // 如果滚动位置距离底部超过10px，认为用户正在查看历史消息
    const isScrolledToBottom =
      messageContainer.value.scrollHeight -
        messageContainer.value.scrollTop -
        messageContainer.value.clientHeight <
      10
    userScrolled.value = !isScrolledToBottom
  }
}
// 滚动到底部
const scrollToBottom = () => {
  nextTick(() => {
    if (messageContainer.value && !userScrolled.value) {
      messageContainer.value.scrollTop = messageContainer.value.scrollHeight
    }
  })
}
watch(
  () => messageList.value,
  () => scrollToBottom(),
  { deep: true },
)
const insertMessage = (content: string, role: role = 'assistant', status?: status): number => {
  const index = messageList.value.length
  messageList.value.push({
    id: index + 1,
    content,
    role,
    status: status || 'normal',
  })
  return index
}
const changeMessage = (
  content: string,
  type: 'new' | 'insert' = 'new',
  index: number = messageList.value.length - 1,
  status?: status,
) => {
  if (type == 'new') {
    messageList.value[index].content = content
  } else {
    messageList.value[index].content += content
  }
  if (status) {
    messageList.value[index].status = status
  }
}
const clearMessage = () => {
  messageList.value = []
}
const insertFile = async (files: File[], index: number = messageList.value.length - 1) => {
  messageList.value[index].files = files
}
defineExpose({
  messageList,
  insertMessage,
  changeMessage,
  clearMessage,
  insertFile,
})
</script>
<template>
  <div class="message-container" ref="messageContainer" @scroll="handleScroll">
    <div
      v-for="item in messageList"
      :key="item.id"
      :class="{
        message: true,
        'assistant-message': item.role === 'assistant',
        'user-message': item.role === 'user',
        error: item.status === 'error',
      }"
    >
      <div class="thinking" v-if="item.role === 'assistant' && item.status === 'thinking'">
        <div class="dot"></div>
        <div class="dot"></div>
        <div class="dot"></div>
      </div>
      <div class="message-content" v-else>
        {{ item.content }}
      </div>
      <div
        class="message-footer"
        v-if="item.role == 'assistant' && item?.files && item?.files?.length > 0"
      >
        <div class="title">参考资料:</div>
        <div class="message-footer-item" v-for="file in item?.files">
          <div class="item">
            <div class="item-title" @click="handleOpenFile(file.url)">
              {{ file.name }}
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<style scoped>
.message-container {
  width: 100%;
  height: 100%;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 1.8vw;
  &::-webkit-scrollbar {
    width: 0.6vw;
    background-color: #f5f5f5;
  }

  &::-webkit-scrollbar-thumb {
    background-color: #dddddd;
    border-radius: 1vw;
  }

  &::-webkit-scrollbar-thumb:hover {
    background-color: #1890ff;
  }
  .message {
    max-width: 80%;
    padding: 1.4vw 1.8vw;
    border-radius: 1.8vw;
    word-break: break-word;
    line-height: 1.6;
    font-size: 1.5vw;
    .message-content {
      min-height: 2.5vw;
      min-width: 1.5vw;
    }
  }
}

.message-footer {
  margin-top: 1.2vw;
}

.message-footer .title {
  font-size: 1.7vw;
  color: #1890ff;
}

.message-footer .item {
  font-size: 1.5vw;
  color: #1890ff;
  margin-top: 0.5vw;
  cursor: pointer;
  text-decoration: underline;
}

.assistant-message {
  align-self: flex-start;
  background: linear-gradient(135deg, #f5f7fa 0%, #f0f2f5 100%);
  border-bottom-left-radius: 0.4vw;
}

.user-message {
  align-self: flex-end;
  background: linear-gradient(135deg, #e6f7ff 0%, #bae7ff 100%);
  color: #0050b3;
  border-bottom-right-radius: 0.4vw;
}

.thinking {
  min-height: 2.5vw;
  display: flex;
  align-self: flex-start;
  align-items: center;
}

.error {
  background: #ffebee;
  border: 1px solid #ffcdd2;
  color: red;
}

.dot {
  height: 8px;
  width: 8px;
  background-color: #757575;
  border-radius: 50%;
  margin: 0 3px;
  opacity: 0.3;
  animation: thinking 1.4s infinite;
}

.dot:nth-child(1) {
  animation-delay: 0s;
}

.dot:nth-child(2) {
  animation-delay: 0.2s;
}

.dot:nth-child(3) {
  animation-delay: 0.4s;
}

@keyframes thinking {
  0%,
  100% {
    opacity: 0.3;
    transform: scale(0.8);
  }
  50% {
    opacity: 1;
    transform: scale(1.2);
  }
}
</style>
